package com.tk.exam.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.tk.exam.bo.QuestionsSortBo;
import com.tk.exam.domain.*;
import com.tk.exam.exception.ApiException;
import com.tk.exam.mapper.*;
import com.tk.exam.service.impl.TkExamManageServiceImpl;
import com.tk.exam.utils.DateUtils;
import com.tk.exam.utils.TokenThreadUtil;
import com.tk.exam.utils.constant.ExamStatusConstant;
import com.tk.exam.utils.constant.QuestionsTypeConstant;
import com.tk.exam.utils.constant.YesOrNoConstant;
import com.tk.exam.vo.question.*;
import com.tk.exam.vo.question.req.TkQuestion4CRequestVo;
import com.tk.exam.vo.question.req.TkQuestionDXRequestVo;
import com.tk.exam.vo.question.req.TkQuestionJSRequestVo;
import com.tk.exam.vo.question.req.TkQuestionPDRequestVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.tk.exam.utils.constant.QuestionsTypeConstant.单选题;


@Service
public class TkStudentServer {

    @Autowired
    TkStudentMapper tkStudentMapper;

    @Autowired
    TkExamNoticeMapper tkExamNoticeMapper;

    @Autowired
    TkExamInfoMapper tkExamInfoMapper;

    @Autowired
    TkQuestionsMapper tkQuestionsMapper;

    @Autowired
    TkStudentAnswerMapper tkStudentAnswerMapper;

    @Autowired
    TkRPaperQuestionMapper tkRPaperQuestionMapper;

    @Autowired
    TkStudentScoreMapper tkStudentScoreMapper;

    @Autowired
    TkExamManageServiceImpl tkExamManageService;

    public List<TkStudent> getByLoginName(String phone) {
        TkStudentExample example = new TkStudentExample();
        example.or().andPhoneNoEqualTo(phone);
        return tkStudentMapper.selectByExample(example);
    }


    public TkExamNotice searchExamNotice() {
        return tkExamNoticeMapper.selectOne();
    }

    /**
     * 根据考试id查询考试信息
     * @param examId
     * @return
     */
    public TkExamInfo searchExamInfo(Integer examId) {
        return tkExamInfoMapper.selectByPrimaryKey(examId);
    }

    /**
     * 根据考试id查询试卷id
     * @param examId
     * @return
     */
    public Integer searchExamPaperId(Integer examId){
        return searchExamInfo(examId).getExamPaperId();
    }


    /**
     * 查询考生Id
     * @return
     */
    public Integer searchStudentId(){
        String userInfoJson = TokenThreadUtil.getTkToken().getTokenInfo();
        Integer studentId = Integer.parseInt(JSON.parseObject(userInfoJson).get("userId")+"");
        return studentId;
    }


    /**
     * 根据学生id和考试id查询考生成绩和考试时间情况
     * @param studentId
     * @param examId
     * @return
     */
    public TkStudentScore searchTkStudentScoreByStudentIdAndExamId(Integer studentId,Integer examId){
        return tkStudentScoreMapper.selectByStudentIdAndExamId(studentId,examId);
    }


    public Map searchExamPaperContent(Integer examId) {
        //查询该场次的考试信息
        TkExamInfo tkExamInfo = searchExamInfo(examId);
        if(Objects.isNull(tkExamInfo)){
           throw ApiException.of("没有匹配的考试场次");
        }
        Map<String,Object> resultMap = new HashMap<>();
        //根据试卷id查询试卷
        Integer examPaperId = tkExamInfo.getExamPaperId();
        //1、单选
        List<QuestionsSortBo> radioQuestionsBos = searchQuestionsBosByExamPaperIdAndType(单选题.getType(),examPaperId);
        //****************************************
        //查询单选题分数
        Double radioScore = searchQuestionsScoreByType(examId, 单选题.getType());

        List<TkQuestionDXRequestVo> radios = new ArrayList<>();
        radioQuestionsBos.forEach(radioQuestionsBo -> {
            String quesContentJson = radioQuestionsBo.getQuesContent();
          if(!StringUtils.isEmpty(quesContentJson)){
              TkQuestionDXRequestVo tkQuestionDXRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionDXRequestVo>() {});
              tkQuestionDXRequestVo.setId(radioQuestionsBo.getId());
              tkQuestionDXRequestVo.setQuestionSocre(radioScore);
              //将答案设置为空
              List<Option> options = tkQuestionDXRequestVo.getOptions();
              options.forEach(option -> {
                  option.setIsCheck(null);
              });
              tkQuestionDXRequestVo.setOptions(options);
              radios.add(tkQuestionDXRequestVo);
          }
        });
        //根据考试id和类型查询该类型试题分数
        resultMap.put("radio",radios);
        //2、判断
        List<QuestionsSortBo> judgeQuestionsBos = searchQuestionsBosByExamPaperIdAndType(QuestionsTypeConstant.判断题.getType(),examPaperId);
        //查询判断题分数
        Double judgeScore = searchQuestionsScoreByType(examId,QuestionsTypeConstant.判断题.getType());
        //*************************************************
        List<TkQuestionPDRequestVo> judge = new ArrayList<>();
        judgeQuestionsBos.forEach(judgeQuestionsBo -> {
            String quesContentJson = judgeQuestionsBo.getQuesContent();
            if (!StringUtils.isEmpty(quesContentJson)) {
                TkQuestionPDRequestVo tkQuestionPDRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionPDRequestVo>() {
                });
                tkQuestionPDRequestVo.setId(judgeQuestionsBo.getId());
                tkQuestionPDRequestVo.setQuestionSocre(judgeScore);
                //将答案设置为空
                tkQuestionPDRequestVo.setChoseType(null);
                judge.add(tkQuestionPDRequestVo);
            }
        });
        resultMap.put("judge",judge);
        //3、填空
        List<QuestionsSortBo> fillBlankQuestionsBos = searchQuestionsBosByExamPaperIdAndType(QuestionsTypeConstant.填空题.getType(),examPaperId);
        //查询填空题分数
        Double fillBlankScore = searchQuestionsScoreByType(examId,QuestionsTypeConstant.填空题.getType());
        //*************************************************
        List<TkQuestionJSRequestVo> fillBlank = new ArrayList<>();
        fillBlankQuestionsBos.forEach(fillBlankQuestionsBo -> {
            String quesContentJson = fillBlankQuestionsBo.getQuesContent();
            if (!StringUtils.isEmpty(quesContentJson)) {
                TkQuestionJSRequestVo tkQuestionTKRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionJSRequestVo>() {
                });
                tkQuestionTKRequestVo.setId(fillBlankQuestionsBo.getId());
                tkQuestionTKRequestVo.setQuestionSocre(fillBlankScore);
                fillBlank.add(tkQuestionTKRequestVo);
            }
        });
        resultMap.put("fillBlank",fillBlank);
        //4、计算
        List<QuestionsSortBo> calculateQuestionsBos = searchQuestionsBosByExamPaperIdAndType(QuestionsTypeConstant.计算题.getType(),examPaperId);
        //查询计算题分数
        Double calculateScore = searchQuestionsScoreByType(examId,QuestionsTypeConstant.计算题.getType());
        //*************************************************
        List<TkQuestionJSRequestVo> calculate = new ArrayList<>();
        calculateQuestionsBos.forEach(calculateQuestionsBo -> {
            String quesContentJson = calculateQuestionsBo.getQuesContent();
            if (!StringUtils.isEmpty(quesContentJson)) {
                TkQuestionJSRequestVo tkQuestionJSRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionJSRequestVo>() {
                });
                tkQuestionJSRequestVo.setId(calculateQuestionsBo.getId());
                tkQuestionJSRequestVo.setQuestionSocre(calculateScore);
                calculate.add(tkQuestionJSRequestVo);
            }
        });
        resultMap.put("calculate",calculate);
        //5、4c
        List<QuestionsSortBo> fourCQuestionsBos = searchQuestionsBosByExamPaperIdAndType(QuestionsTypeConstant.四C题.getType(),examPaperId);
        //************************************************
        //查询四C题分数
        Double fourCScore = searchQuestionsScoreByType(examId,QuestionsTypeConstant.四C题.getType());
        List<TkQuestion4CRequestVo> fourC = new ArrayList<>();
        fourCQuestionsBos.forEach(fourCQuestionsBo -> {
            String quesContentJson = fourCQuestionsBo.getQuesContent();
            if (!StringUtils.isEmpty(quesContentJson)) {
                TkQuestion4CRequestVo tkQuestion4CRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestion4CRequestVo>() {
                });
                tkQuestion4CRequestVo.setId(fourCQuestionsBo.getId());
                //将答案设置为空
                tkQuestion4CRequestVo.setHasDefect(null);

                List<Option> options = tkQuestion4CRequestVo.getOptions();
                options.forEach(option -> {
                    option.setIsCheck(null);
                });
                tkQuestion4CRequestVo.setOptions(options);

                List<SupportDeviceImage> supportDeviceImages = tkQuestion4CRequestVo.getSupportDeviceImages();
               if(!CollectionUtils.isEmpty(supportDeviceImages)){
                   supportDeviceImages.forEach(supportDeviceImage -> {
                       supportDeviceImage.setHasCheck(null);
                   });
                   tkQuestion4CRequestVo.setSupportDeviceImages(supportDeviceImages);
               }

                List<CatenaryImage> catenaryImages = tkQuestion4CRequestVo.getCatenaryImages();
               if(!CollectionUtils.isEmpty(catenaryImages)){
                   catenaryImages.forEach(catenaryImage -> {
                       catenaryImage.setHasCheck(null);
                   });
                   tkQuestion4CRequestVo.setCatenaryImages(catenaryImages);
               }

                List<AddSuspensionImage> addSuspensionImages = tkQuestion4CRequestVo.getAddSuspensionImages();
               if(!CollectionUtils.isEmpty(addSuspensionImages)){
                   addSuspensionImages.forEach(addSuspensionImage -> {
                       addSuspensionImage.setHasCheck(null);
                   });
                   tkQuestion4CRequestVo.setAddSuspensionImages(addSuspensionImages);
               }

                List<DavitImage> davitImages = tkQuestion4CRequestVo.getDavitImages();
               if(!CollectionUtils.isEmpty(davitImages)){
                   davitImages.forEach(davitImage -> {
                       davitImage.setHasCheck(null);
                   });
                   tkQuestion4CRequestVo.setDavitImages(davitImages);
               }
                tkQuestion4CRequestVo.setQuestionSocre(fourCScore);
                fourC.add(tkQuestion4CRequestVo);
            }
        });

        resultMap.put("fourC",fourC);

        return resultMap;
    }

    private Double searchQuestionsScoreByType(Integer examId, Byte type) {
        return tkRPaperQuestionMapper.searchQuestionsScoreByType(examId,type);
    }

    /**
     * 根据试卷id和试题类型获取试题 并按试题顺序排序
     * @return
     */
    private  List<QuestionsSortBo> searchQuestionsBosByExamPaperIdAndType(Byte type,Integer examPaperId){
        List<QuestionsSortBo> questionsSortBos = tkQuestionsMapper.selectByExamPaperIdAndQuestionType(type,examPaperId);
        Collections.sort(questionsSortBos);
        return questionsSortBos;
    }


    public void submitJudgeAnswer(Integer examId,TkQuestionPDRequestVo object) {

        //校验该学生是否在考试状态
        validateExaming(examId);
        calculateJudge(examId, object);
    }

    @Transactional(rollbackFor = Exception.class)
    public void calculateJudge(Integer examId, TkQuestionPDRequestVo object) {
        //查询试卷id
        Integer examPaperId = searchExamPaperId(examId);
        //查询考生id
        Integer studentId = searchStudentId();

        //计算分数
        Integer questionId = object.getId();
        TkQuestions tkQuestions = tkQuestionsMapper.selectByPrimaryKey(questionId);
        String quesContentJson = tkQuestions.getQuesContent();
        TkQuestionPDRequestVo tkQuestion4CRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionPDRequestVo>() {});
        //根据考试id、试题id、学生id查询考生试题结果
        TkStudentAnswer tkStudentAnswer = tkStudentAnswerMapper.selectByExamIdAndPaperIdAndStudentId(examId,questionId,studentId);
        if(Objects.isNull(tkStudentAnswer)){
            tkStudentAnswer = new TkStudentAnswer(examId,questionId,studentId,JSON.toJSONString(object));
        }else {
            tkStudentAnswer.setAnswer(JSON.toJSONString(object));
        }

        //比较学生答案和正确答案
        if(!object.getChoseType().equals(tkQuestion4CRequestVo.getChoseType())){
            tkStudentAnswer.setScore(new Double(0));
        }else{
            TkRPaperQuestion tkRPaperQuestion = tkRPaperQuestionMapper.selectByPaperIdAndQuestionId(examPaperId,questionId);
            tkStudentAnswer.setScore(tkRPaperQuestion.getQuestionSocre());
        }
        //保存结果
        saveTkStudentAnswer(tkStudentAnswer);
    }

    private void validateExaming(Integer examId) {
        if(!isExaming(examId)){
            throw ApiException.of("本场考试已结束");
        }
    }

    private void saveTkStudentAnswer(TkStudentAnswer tkStudentAnswer) {
        if(!Objects.isNull(tkStudentAnswer.getId())&&tkStudentAnswer.getId()!=0){
            tkStudentAnswer.setUpdateTime(new Date());
            tkStudentAnswerMapper.updateByPrimaryKey(tkStudentAnswer);
        }else {
            tkStudentAnswer.setCreateTime(new Date());
            tkStudentAnswer.setUpdateTime(new Date());
            tkStudentAnswerMapper.insert(tkStudentAnswer);
        }

    }


    public void submitRadioAnswer(Integer examId,TkQuestionDXRequestVo object) {
        //校验该学生是否在考试状态
        validateExaming(examId);
        calculateRadio(examId, object);
    }

    @Transactional(rollbackFor = Exception.class)
    public void calculateRadio(Integer examId, TkQuestionDXRequestVo object) {
        //查询试卷id
        Integer examPaperId = searchExamPaperId(examId);
        //查询考生id
        Integer studentId = searchStudentId();

        //计算分数
        Integer questionId = object.getId();
        TkQuestions tkQuestions = tkQuestionsMapper.selectByPrimaryKey(questionId);
        String quesContentJson = tkQuestions.getQuesContent();
        TkQuestionDXRequestVo tkQuestionDXRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestionDXRequestVo>() {});
        //根据考试id、试题id、学生id查询考生试题结果
        TkStudentAnswer tkStudentAnswer = tkStudentAnswerMapper.selectByExamIdAndPaperIdAndStudentId(examId,questionId,studentId);
        if(Objects.isNull(tkStudentAnswer)){
            tkStudentAnswer = new TkStudentAnswer(examId,questionId,studentId,JSON.toJSONString(object));
        }else{
            tkStudentAnswer.setAnswer(JSON.toJSONString(object));
        }
        //比较学生答案和正确答案
        List<Option> options = object.getOptions();
        List<Option> answerOptions = tkQuestionDXRequestVo.getOptions();
        String rightFlag = "";
        for(Option answerOption:answerOptions){
            if(answerOption.getIsCheck().equals(YesOrNoConstant.是.getStatus())){
                rightFlag = answerOption.getContent();
            }
        }

        boolean right = false;
        for(Option option:options){
            if(option.getContent().equals(rightFlag)){
                right = option.getIsCheck().equals("1")?true:false;
            }
        }

        if(!right){
            tkStudentAnswer.setScore(new Double(0));
        }else{
            TkRPaperQuestion tkRPaperQuestion = tkRPaperQuestionMapper.selectByPaperIdAndQuestionId(examPaperId,questionId);
            tkStudentAnswer.setScore(tkRPaperQuestion.getQuestionSocre());
        }
        //保存结果
        saveTkStudentAnswer(tkStudentAnswer);
    }


    public void submitFourCAnswer(Integer examId,TkQuestion4CRequestVo object) {
        //校验该学生是否在考试状态
        validateExaming(examId);
        calculateFourC(examId, object);
    }

    @Transactional(rollbackFor = Exception.class)
    public void calculateFourC(Integer examId, TkQuestion4CRequestVo object) {
        //查询试卷id
        Integer examPaperId = searchExamPaperId(examId);
        //查询考生id
        Integer studentId = searchStudentId();

        //计算分数
        Integer questionId = object.getId();
        TkQuestions tkQuestions = tkQuestionsMapper.selectByPrimaryKey(questionId);
        //没有该试题
        if(Objects.isNull(tkQuestions)){
            throw ApiException.of("没有该试题");
        }
        String quesContentJson = tkQuestions.getQuesContent();
        TkQuestion4CRequestVo tkQuestion4CRequestVo = JSON.parseObject(quesContentJson, new TypeReference<TkQuestion4CRequestVo>() {});
        //根据考试id、试题id、学生id查询考生试题结果
        TkStudentAnswer tkStudentAnswer = tkStudentAnswerMapper.selectByExamIdAndPaperIdAndStudentId(examId,questionId,studentId);
        if(Objects.isNull(tkStudentAnswer)){
            tkStudentAnswer = new TkStudentAnswer(examId,questionId,studentId,JSON.toJSONString(object));
        }else{
            tkStudentAnswer.setAnswer(JSON.toJSONString(object));
        }

        boolean right;
        //比较学生答案和正确答案
        //是否存在缺陷--对比
        right = object.getHasDefect().equals(tkQuestion4CRequestVo.getHasDefect())?true:false;
        //缺陷类型--对比
        if(right){
            String rightContent = "";
            List<Option> options = object.getOptions();
            for(Option option : options){
               if( option.getIsCheck().equals(YesOrNoConstant.是.getStatus())){
                   rightContent = option.getContent();
                   break;
               }
            }
            List<Option> answerOptions = tkQuestion4CRequestVo.getOptions();
            for(Option answerOption : answerOptions){
                String content = answerOption.getContent();
                //校验如果选项为空跳过
                if(StringUtils.isEmpty(content)){
                    continue;
                }
                if(content.equals(rightContent)&&answerOption.getIsCheck().equals(YesOrNoConstant.是.getStatus())){
                    right = true;
                    break;
                }else{
                    right = false;
                }
            }
        }

        //对比所选图片
        //标记4c题选择正确情况
        boolean option4CFlag = false;
        List<String> answerList = new ArrayList<>();
        List<AddSuspensionImage> addSuspensionImages = tkQuestion4CRequestVo.getAddSuspensionImages();
        List<CatenaryImage> catenaryImages = tkQuestion4CRequestVo.getCatenaryImages();
        List<DavitImage> davitImages = tkQuestion4CRequestVo.getDavitImages();
        List<SupportDeviceImage> supportDeviceImages = tkQuestion4CRequestVo.getSupportDeviceImages();

        for(AddSuspensionImage addSuspensionImage : addSuspensionImages){
            if(addSuspensionImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())){
                answerList.add(addSuspensionImage.getImageId());
            }
        }

        for(CatenaryImage catenaryImage : catenaryImages){
            if(catenaryImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())){
                answerList.add(catenaryImage.getImageId());
            }
        }

        for(DavitImage davitImage : davitImages){
            if(davitImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())){
                answerList.add(davitImage.getImageId());
            }
        }

        for(SupportDeviceImage supportDeviceImage: supportDeviceImages){
            if(supportDeviceImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())){
                answerList.add(supportDeviceImage.getImageId());
            }
        }

        List<AddSuspensionImage> addSuspensionImagesResult = object.getAddSuspensionImages();
        List<CatenaryImage> catenaryImagesResult = object.getCatenaryImages();
        List<DavitImage> davitImagesResult = object.getDavitImages();
        List<SupportDeviceImage> supportDeviceImagesResult = object.getSupportDeviceImages();

        for(AddSuspensionImage addSuspensionImage :addSuspensionImagesResult) {
            if(addSuspensionImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())&&answerList.contains(addSuspensionImage.getImageId())){
                option4CFlag = true;
                continue;
            }
        }

        if(!option4CFlag){
            for(CatenaryImage catenaryImage : catenaryImagesResult){
                 if(catenaryImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())&&answerList.contains(catenaryImage.getImageId())){
                     option4CFlag = true;
                     continue;
                 }
            }
        }

        if(!option4CFlag){
           for(DavitImage davitImage : davitImagesResult){
               if(davitImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())&&answerList.contains(davitImage.getImageId())){
                   option4CFlag = true;
                   continue;
               }
           }
        }

        if(!option4CFlag){
            for(SupportDeviceImage supportDeviceImage : supportDeviceImagesResult){
                if(supportDeviceImage.getHasCheck().equals(YesOrNoConstant.是.getStatus())&&answerList.contains(supportDeviceImage.getImageId())){
                    option4CFlag = true;
                    continue;
                }
            }
        }

        if(right&&option4CFlag){
            TkRPaperQuestion tkRPaperQuestion = tkRPaperQuestionMapper.selectByPaperIdAndQuestionId(examPaperId,questionId);
            tkStudentAnswer.setScore(tkRPaperQuestion.getQuestionSocre());
        }else{
            tkStudentAnswer.setScore(new Double(0));
        }
        //保存结果
        saveTkStudentAnswer(tkStudentAnswer);
    }



    /**
     * 根据考试id查询该场次是否处于考试中状态
     * @param examId
     * @return
     */
    public Boolean isExaming(Integer examId){
        return searchExamStatus(examId)==2? true: false;
    }

    /**
     * 根据考试id查询该场次所处的状态
     * @param examId
     * @return  1:未开始,2:进行中,3:已结束
     */
    public Integer searchExamStatus(Integer examId){
        TkExamInfo tkExamInfo = searchExamInfo(examId);
        if(tkExamInfo.getExamStatus().equals(ExamStatusConstant.已结束.getStatus())){
            return 3;
        }
        //获取当前时间
        Date now = DateUtils.now();
        //当前时间和开考时间比较：小于开考时间则未开始考试
        if(now.getTime()<tkExamInfo.getExamTime().getTime()){
            tkExamInfo.setExamStatus(new Byte("1"));
            tkExamInfoMapper.updateByPrimaryKey(tkExamInfo);
            return 1;
        }

        /**
         * 开考时间+考试时长+允许最大迟到时间 与 当前时间比较 小于 则 考试结束
         *  考试时长延长#{迟到}分钟
         */

        if((tkExamInfo.getExamTime().getTime()+DateUtils.minuteToMillisecond(tkExamInfo.getExamTotalTime()+tkExamInfo.getMaxLateTime()))< DateUtils.now().getTime()){
            tkExamInfo.setExamStatus(new Byte("3"));
            tkExamInfoMapper.updateByPrimaryKey(tkExamInfo);
            return 3;
        }
        return 2;
    }


    /**
     * 根据考试id查询题目数量
     * @param examId
     * @return
     */
    private Integer searchQuestionNumByExamId(Integer examId){
        return tkRPaperQuestionMapper.countByExamId(examId);
    }

    /**
     * 根据考试id查询线上题目数量
     * @param examId
     * @return
     */
    private Integer searchOnlineQuestionNumByExamId(Integer examId){
        List<Byte> questionTypes = new ArrayList<>();
        questionTypes.add(QuestionsTypeConstant.单选题.getType());
        questionTypes.add(QuestionsTypeConstant.判断题.getType());
        questionTypes.add(QuestionsTypeConstant.四C题.getType());
        return tkRPaperQuestionMapper.countByExamIdAndQuestionTypes(examId,questionTypes);
    }



    /**
     * 根据考试id查询考生所做题目数量
     * @param examId
     * @return
     */
    private Integer searchResultNumByExamIdAndStudentId(Integer examId,Integer studentId){
        return tkStudentAnswerMapper.countByExamIdAndStudentId(examId,studentId);
    }


    @Transactional(rollbackFor = Exception.class)
    public void commitExamPaper(Integer examId,Boolean commitFlag) {
        //校验本场考试是否在进行中
//        validateExaming(examId);

        //校验考生是否已经超时
        Integer studentId = searchStudentId();
        TkExamInfo tkExamInfo = searchExamInfo(examId);
        TkStudentScore tkStudentScore = searchTkStudentScoreByStudentIdAndExamId(studentId,examId);
//        if(DateUtils.now().getTime() > (tkStudentScore.getStartTime().getTime()+DateUtils.minuteToMillisecond(tkExamInfo.getExamTotalTime()+1))){
//            throw ApiException.of("考试已结束，不允许提交试卷");
//        }
        if(Objects.isNull(tkStudentScore)){
            throw  ApiException.of("状态异常，考生还没有开始考试，无法提交试卷！");
        }

        //校验该考生是否已经做完
        if(!Objects.isNull(commitFlag)&&!commitFlag){
            //查询题目数量
            Integer examPaperId = tkExamInfo.getExamPaperId();
//            List<TkRPaperQuestion> tkRPaperQuestions = tkRPaperQuestionMapper.selectByPaperId(examPaperId);
            //线上试题类型
            List<Byte> questionTypes = new ArrayList<>();
            questionTypes.add(QuestionsTypeConstant.单选题.getType());
            questionTypes.add(QuestionsTypeConstant.判断题.getType());
            questionTypes.add(QuestionsTypeConstant.四C题.getType());
            List<TkRPaperQuestion> tkRPaperQuestions = tkRPaperQuestionMapper.selectByPaperIdAndQuestionTypes(examPaperId,questionTypes);
            //查询结果数量
            //查询考生做题结果
            Integer StudentExamResultNum =  searchStudentExamResultNum(examId,studentId);
            if(StudentExamResultNum!=tkRPaperQuestions.size()){
                throw  ApiException.of("您还有试题未答完");
            }
        }
        //计算总分
        Double score = searchStudentExamTotalScore(examId,studentId);
        //保存结果
        tkStudentScore.setOnlineSocre(score);
        Double offlineSocre = tkStudentScore.getOfflineSocre()==null?new Double(0):tkStudentScore.getOfflineSocre();
        tkStudentScore.setTotalSocre(score+offlineSocre);
        tkStudentScore.setEndTime(new Date());
        saveTkStudentScore(tkStudentScore);
    }

    /**
     * 计算该考生本次考试的总分数
     * @param examId
     * @param studentId
     * @return
     */
    private Double searchStudentExamTotalScore(Integer examId, Integer studentId) {
        return tkStudentAnswerMapper.searchStudentExamTotalScore(examId,studentId);
    }

    /**
     * 查询本次考试该考生所做题目的数量
     * @param examId
     * @param studentId
     * @return
     */
    private Integer searchStudentExamResultNum(Integer examId, Integer studentId) {
        return tkStudentAnswerMapper.searchStudentExamResultNum(examId,studentId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveTkStudentScore(TkStudentScore tkStudentScore) {
        if(!Objects.isNull(tkStudentScore.getId())&&tkStudentScore.getId()!=0){
            tkStudentScoreMapper.updateByPrimaryKey(tkStudentScore);
        }else{
            tkStudentScoreMapper.insert(tkStudentScore);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void startExam(Integer examId) {
        //校验是否超过最大迟到时间
        validateLateTime(examId);
        //记录开始考试时间
        Integer studentId = searchStudentId();
        TkStudentScore tkStudentScore = searchTkStudentScoreByStudentIdAndExamId(studentId,examId);
        if(!Objects.isNull(tkStudentScore)){
            deleteTkStudentScoreById(tkStudentScore.getId());
        }
        tkStudentScore = new TkStudentScore(studentId,examId,new Double(0),new Double(0),new Double(0),new Date());
        //保存数据
        saveTkStudentScore(tkStudentScore);
    }

    private void validateLateTime(Integer examId) {
        TkExamInfo tkExamInfo = searchExamInfo(examId);
        long startTime = tkExamInfo.getExamTime().getTime();
        Long lateTime = DateUtils.minuteToMillisecond(tkExamInfo.getMaxLateTime());
        long nowTime = DateUtils.now().getTime();
        if(nowTime<startTime){
            throw ApiException.of("考试未开始");
        }
        if(nowTime > (startTime+lateTime)){
            throw ApiException.of("考试已经开始 "+tkExamInfo.getMaxLateTime()+" 分钟,不允许答题。");
        }
    }

    private void deleteTkStudentScoreById(Integer id){
        tkStudentScoreMapper.deleteByPrimaryKey(id);
    }

    public Map<String, Object> searchExamCompleteInfo(Integer examId) {
        Map<String,Object> resultMap = new HashMap<>();
        //查询线上考试题目数量
        Integer problemNum = searchOnlineQuestionNumByExamId(examId);
        //查询考生所做题数量
        Integer studentId = searchStudentId();
        Integer resultNum = searchResultNumByExamIdAndStudentId(examId,studentId);
        //查询考生用时
        TkStudentScore tkStudentScore = searchTkStudentScoreByStudentIdAndExamId(studentId, examId);
        Date startTime = tkStudentScore.getStartTime();
        Date endTime = tkStudentScore.getEndTime();
        if(!Objects.isNull(startTime)&&!Objects.isNull(endTime)){
            Integer usedMinute = DateUtils.getTimeDifference2Minute(startTime,endTime);
            resultMap.put("usedMinute",usedMinute);
        }

        resultMap.put("finished",resultNum);
        resultMap.put("unfinished",problemNum - resultNum);
        return resultMap;
    }

    @Transactional(rollbackFor = Exception.class)
    public void repeatCalculate(Integer examId,Integer studentId) {
        //查询所有选择题
        List<TkStudentAnswer> dxAnswers = searchResultByExamIdAndTypeAndStudentId(单选题.getType(),examId,studentId);
        dxAnswers.forEach(dxAnswer -> {
            TkQuestionDXRequestVo tkQuestionDXRequestVo = JSON.parseObject(dxAnswer.getAnswer(), new TypeReference<TkQuestionDXRequestVo>() {});
            calculateRadio(examId,tkQuestionDXRequestVo);
        });
        //查询所有判断题
        List<TkStudentAnswer> pdAnswers = searchResultByExamIdAndTypeAndStudentId(QuestionsTypeConstant.判断题.getType(),examId,studentId);
        pdAnswers.forEach(pdAnswer -> {
            TkQuestionPDRequestVo tkQuestionPDRequestVo = JSON.parseObject(pdAnswer.getAnswer(), new TypeReference<TkQuestionPDRequestVo>() {});
            calculateJudge(examId,tkQuestionPDRequestVo);
        });
        //查询所有4c题
        List<TkStudentAnswer> fourCAnswers = searchResultByExamIdAndTypeAndStudentId(QuestionsTypeConstant.四C题.getType(),examId,studentId);
        fourCAnswers.forEach(fourCAnswer -> {
            TkQuestion4CRequestVo tkQuestion4CRequestVo = JSON.parseObject(fourCAnswer.getAnswer(), new TypeReference<TkQuestion4CRequestVo>() {});
            calculateFourC(examId,tkQuestion4CRequestVo);
        });
        //重新计算并保存总分
        sumAndSaveStudentScore(examId,studentId);

    }

    private void sumAndSaveStudentScore(Integer examId, Integer studentId) {
        TkStudentScore tkStudentScore = searchTkStudentScoreByStudentIdAndExamId(studentId, examId);
        Double score = searchStudentExamTotalScore(examId, studentId);
        tkStudentScore.setOnlineSocre(score);
        tkStudentScore.setTotalSocre(tkStudentScore.getOfflineSocre()+score);
        saveTkStudentScore(tkStudentScore);
    }

    private List<TkStudentAnswer> searchResultByExamIdAndTypeAndStudentId(Byte type, Integer examId, Integer studentId) {
        return tkStudentAnswerMapper.selectByExamIdAndTypeAndStudentId(type,examId,studentId);
    }

    public Map<String,Object> validateLoginBusiness(TkStudent tkStudent) {
        Map<String,Object> resultMap = new HashMap<>();
        Integer classId = tkStudent.getClassId();
        //获取当前时间前一场考试
        TkExamInfo lessTkExamInfo = tkExamInfoMapper.selectOneLessEqualNowTime(classId,DateUtils.now());
        //获取当前时间后一场考试
        TkExamInfo moreTkExamInfo = tkExamInfoMapper.selectOneMoreNowTime(classId,DateUtils.now());

        if(Objects.isNull(lessTkExamInfo)&&Objects.isNull(moreTkExamInfo)){//左右都没有
            //当前无考试信息
            resultMap.put("type",1);
        }else if(!Objects.isNull(lessTkExamInfo)&&Objects.isNull(moreTkExamInfo)){//左有右没有
            //获取该场考试结束时间的毫秒值
            long endExamTime = lessTkExamInfo.getExamTime().getTime() + DateUtils.minuteToMillisecond(lessTkExamInfo.getMaxLateTime() + lessTkExamInfo.getExamTotalTime());
            if(endExamTime > DateUtils.now().getTime()){
                //考试中
                examing(resultMap,lessTkExamInfo.getId(),tkStudent.getId(),lessTkExamInfo,null);
            }else {
                //考试结束
                examEnd(resultMap, lessTkExamInfo,tkStudent.getId());
            }
        }else if(Objects.isNull(lessTkExamInfo)&&!Objects.isNull(moreTkExamInfo)){//左没有右有
            //考试未开始
            examNoStart(resultMap, moreTkExamInfo);
        }else{//左右都有
            //获取该场考试结束时间的毫秒值
            long endExamTime = lessTkExamInfo.getExamTime().getTime() + DateUtils.minuteToMillisecond(lessTkExamInfo.getMaxLateTime() + lessTkExamInfo.getExamTotalTime());
            if(endExamTime > DateUtils.now().getTime()){
                //考试中
                examing(resultMap,moreTkExamInfo.getId(),tkStudent.getId(),lessTkExamInfo,moreTkExamInfo);
            }else {
                //考试未开始
                examNoStart(resultMap, moreTkExamInfo);
            }
        }
        return resultMap;
    }

    private void examNoStart(Map<String, Object> resultMap, TkExamInfo moreTkExamInfo) {
        resultMap.put("type",3);
        resultMap.put("examId",moreTkExamInfo.getId());
        resultMap.put("examName",moreTkExamInfo.getExamName());
        resultMap.put("examTime", DateUtils.formate(moreTkExamInfo.getExamTime()));
    }

    private void examEnd(Map<String, Object> resultMap, TkExamInfo lessTkExamInfo,Integer studentId) {
        resultMap.put("type",2);
        resultMap.put("examName",lessTkExamInfo.getExamName());
        resultMap.put("examTime", DateUtils.toTimeInterval(lessTkExamInfo.getExamTime(),lessTkExamInfo.getExamTotalTime()));
        resultMap.put("examingTime",searchExamingTime(lessTkExamInfo.getId(),studentId));
        resultMap.put("finished",searchResultNumByExamIdAndStudentId(lessTkExamInfo.getId(),studentId));
        resultMap.put("unfinished",searchQuestionNumByExamId(lessTkExamInfo.getId()) - searchResultNumByExamIdAndStudentId(lessTkExamInfo.getId(),studentId));
    }

    private void examing(Map<String, Object> resultMap,Integer examId,Integer studentId,TkExamInfo lessTkExamInfo, TkExamInfo moreTkExamInfo) {
        //校验考试是否已经提交试卷
        TkStudentScore tkStudentScore = tkStudentScoreMapper.selectByStudentIdAndExamId(studentId, examId);
        //考生已经结束考试
        if(!Objects.isNull(tkStudentScore)&&!Objects.isNull(tkStudentScore.getEndTime())){
            if(Objects.isNull(moreTkExamInfo)){//考试结束
                examEnd(resultMap, lessTkExamInfo,studentId);
            }else {//考试未开始
                examNoStart(resultMap, moreTkExamInfo);
            }
        }

        //考生开始考试，异常断电等情况，考生重新登录考试
        if(!Objects.isNull(tkStudentScore)){
            Date startTime = tkStudentScore.getStartTime();
            resultMap.put("startTime",startTime);
        }
        resultMap.put("examId",examId);
        resultMap.put("type",4);
    }

    /**
     * 根据考试id和学生id查询该考生 考试用时 单位:分钟
     * @param examId
     * @param studentId
     * @return
     */
    private Integer searchExamingTime(Integer examId,Integer studentId){
        TkStudentScore tkStudentScore = tkStudentScoreMapper.selectByStudentIdAndExamId(studentId, examId);
        if(Objects.isNull(tkStudentScore)){
            return 0;
        }
        Date startTime = tkStudentScore.getStartTime();
        Date endTime = tkStudentScore.getEndTime();
        if(Objects.isNull(startTime)||Objects.isNull(endTime)){
            return 0;
        }
        return DateUtils.getTimeDifference2Minute(startTime,endTime);
    }

    public Map<String,Object> searchRemainTime(Integer examId) {
        Map<String,Object> resultMap = new HashMap<>();
        //根据考试id查询考试详情
        TkExamInfo tkExamInfo = searchExamInfo(examId);
        //考试时长
        Integer examTotalTime = tkExamInfo.getExamTotalTime();
        //当前时间 - 开始时间 >= 考试时长
        Integer studentId = searchStudentId();
        //查询考生考试开始时间
        TkStudentScore tkStudentScore = searchTkStudentScoreByStudentIdAndExamId(studentId, examId);
        //获取当前时间
        Date nowTime = DateUtils.now();

        //当前考生没有考试或者考试时长用完返回0
        if(Objects.isNull(tkStudentScore)||
                DateUtils.getTimeDifference2Minute(tkStudentScore.getStartTime(),nowTime) >= examTotalTime){
            resultMap.put("secondUnit",0);
            resultMap.put("millisecondUnit",0);
            return resultMap;
        }
        //考试开始时间
        Date startTime = tkStudentScore.getStartTime();
        Date endTime = DateUtils.toNewTime(startTime, examTotalTime);
        //考试结束时间
        resultMap.put("secondUnit",DateUtils.getTimeDifference2Second(nowTime,endTime));
        resultMap.put("millisecondUnit",DateUtils.getTimeDifference2Millisecond(nowTime,endTime));
        return resultMap;
    }

    public TkStudent getStudentByAll(List<TkStudent> tkStudents) {
        Map<Integer,TkStudent> studentMap = new HashMap<>();
        tkStudents.forEach( tkStudent -> {
            studentMap.put(tkStudent.getClassId(),tkStudent);
        });
        Set<Integer> classIds = studentMap.keySet();
        //刷新考试状态
        tkExamManageService.updateExamStatus();
        //根据班级查询信息
        TkStudent student;
        TkExamInfo tkExamInfo = tkExamInfoMapper.selectOneByClassIdsAndTypeASC(classIds,ExamStatusConstant.进行中.getStatus());

        if(!Objects.isNull(tkExamInfo)){
            student = studentMap.get(tkExamInfo.getClassId());
            return student;
        }

        tkExamInfo = tkExamInfoMapper.selectOneByClassIdsAndTypeASC(classIds,ExamStatusConstant.未开始.getStatus());
        if(!Objects.isNull(tkExamInfo)){
            student = studentMap.get(tkExamInfo.getClassId());
            return student;
        }else{
            tkExamInfo = tkExamInfoMapper.selectOneByClassIdsAndTypeDESC(classIds, ExamStatusConstant.已结束.getStatus());
            if (!Objects.isNull(tkExamInfo)) {
                student = studentMap.get(tkExamInfo.getClassId());
                return student;
            } else {
                return tkStudents.get(0);
            }
        }

    }
}
